package com.liting.uitest.imgutils;

import com.liting.uitest.model.LabColor;

import java.awt.color.ColorSpace;

public class RGBtoLAB {
    private static final double REF_X = 0.95047;
    private static final double REF_Y = 1.0;
    private static final double REF_Z = 1.08883;

    private static final double EPSILON = 0.008856;
    private static final double KAPPA = 903.3;

    // RGB到XYZ的转换矩阵
    private static final double[][] RGB_TO_XYZ = {
            {0.4124564, 0.3575761, 0.1804375},
            {0.2126729, 0.7151522, 0.0721750},
            {0.0193339, 0.1191920, 0.9503041}
    };

    // XYZ到LAB的转换
    public static LabColor xyzToLab(double x, double y, double z) {
        double fx, fy, fz;

        if (x > EPSILON) fx = Math.pow(x / REF_X, 1.0 / 3.0);
        else fx = (KAPPA * x / REF_X) + 4.0 / 29.0;
        if (y > EPSILON) fy = Math.pow(y / REF_Y, 1.0 / 3.0);
        else fy = (KAPPA * y / REF_Y) + 4.0 / 29.0;
        if (z > EPSILON) fz = Math.pow(z / REF_Z, 1.0 / 3.0);
        else fz = (KAPPA * z / REF_Z) + 4.0 / 29.0;

        double l = 116.0 * fy - 16.0;
        double a = 500.0 * (fx - fy);
        double b = 200.0 * (fy - fz);

        LabColor labColor = new LabColor(l, a, b);


        return labColor;
    }

    public static LabColor rgbToLab3(int R, int G, int B) {
        double r = R / 255.000; // rgb range: 0 ~ 1
        double g = G / 255.000;
        double b = B / 255.000;


        // gamma 2.2
        if (r > 0.04045)
            r = Math.pow((r + 0.055) / 1.055, 2.4);
        else
            r = r / 12.92;
        if (g > 0.04045)
            g = Math.pow((g + 0.055) / 1.055, 2.4);
        else
            g = g / 12.92;
        if (b > 0.04045)
            b = Math.pow((b + 0.055) / 1.055, 2.4);
        else
            b = b / 12.92;


        // sRGB
        double X = r * 0.436052025 + g * 0.385081593 + b * 0.143087414;
        double Y = r * 0.222491598 + g * 0.716886060 + b * 0.060621486;
        double Z = r * 0.013929122 + g * 0.097097002 + b * 0.714185470;


        // XYZ range: 0~100
        X = X * 100.000;
        Y = Y * 100.000;
        Z = Z * 100.000;


        // Reference White Point
        double ref_X = 96.4221;
        double ref_Y = 100.000;
        double ref_Z = 82.5211;

        X = X / ref_X;
        Y = Y / ref_Y;
        Z = Z / ref_Z;


        // Lab
        if (X > 0.008856)
            X = Math.pow(X, 1 / 3.000);
        else
            X = (7.787 * X) + (16 / 116.000);
        if (Y > 0.008856)
            Y = Math.pow(Y, 1 / 3.000);
        else
            Y = (7.787 * Y) + (16 / 116.000);
        if (Z > 0.008856)
            Z = Math.pow(Z, 1 / 3.000);
        else
            Z = (7.787 * Z) + (16 / 116.000);


        double Lab_L = (116.000 * Y) - 16.000;
        double Lab_A = 500.000 * (X - Y);
        double Lab_B = 200.000 * (Y - Z);

        LabColor labColor = new LabColor(Lab_L, Lab_A, Lab_B);
        return labColor;

    }

    public static LabColor rgbToLab2(int r, int g, int b) {
        // 将RGB值归一化到0-1范围
        double rNorm = r / 255.0;
        double gNorm = g / 255.0;
        double bNorm = b / 255.0;

        // RGB到XYZ转换
        double x = RGB_TO_XYZ[0][0] * rNorm + RGB_TO_XYZ[0][1] * gNorm + RGB_TO_XYZ[0][2] * bNorm;
        double y = RGB_TO_XYZ[1][0] * rNorm + RGB_TO_XYZ[1][1] * gNorm + RGB_TO_XYZ[1][2] * bNorm;
        double z = RGB_TO_XYZ[2][0] * rNorm + RGB_TO_XYZ[2][1] * gNorm + RGB_TO_XYZ[2][2] * bNorm;
        ColorSpace labColorSpace = ColorSpace.getInstance(ColorSpace.CS_CIEXYZ);
        float[] lab = new float[3];
        // Convert RGB to Lab
        float[] rgb = new float[3];
        rgb[0] = (float) rNorm;
        rgb[1] = (float) gNorm;
        rgb[2] = (float) bNorm;

        lab = labColorSpace.fromRGB(rgb);

        LabColor labColor = new LabColor(lab[0], lab[1], lab[2]);
        return labColor;
    }

    public static LabColor rgbToLab(int r, int g, int b) {
        // 将RGB值归一化到0-1范围
        double rNorm = r / 255.0;
        double gNorm = g / 255.0;
        double bNorm = b / 255.0;

        // RGB到XYZ转换
        double x = RGB_TO_XYZ[0][0] * rNorm + RGB_TO_XYZ[0][1] * gNorm + RGB_TO_XYZ[0][2] * bNorm;
        double y = RGB_TO_XYZ[1][0] * rNorm + RGB_TO_XYZ[1][1] * gNorm + RGB_TO_XYZ[1][2] * bNorm;
        double z = RGB_TO_XYZ[2][0] * rNorm + RGB_TO_XYZ[2][1] * gNorm + RGB_TO_XYZ[2][2] * bNorm;


        // XYZ到LAB转换
        return xyzToLab(x, y, z);
    }

    public static void main(String[] args) {
        int r = 255;
        int g = 0;
        int b = 0;

        LabColor lab = rgbToLab(r, g, b);


        LabColor lab2 = rgbToLab(100, 10, 10);
        double distance = ColorDistance.calculateColorDifference(lab, lab2);

        System.out.println(distance);
        //System.out.println("LAB: L=" + lab.L + ", A=" + lab.a + ", B=" + lab.b);
    }
}
